package com.welike.shibo.aspect;

import com.welike.shibo.aspect.annotation.AutoLog;
import com.welike.shibo.eneity.Log;
import com.welike.shibo.eneity.SysUser;
import com.welike.shibo.eneity.User;
import com.welike.shibo.service.LogService;
import com.welike.shibo.utils.Constants;
import com.welike.shibo.utils.IpUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 系统日志切面
 * 使用@Aspect注解声明一个切面
 * @author fangyu
 * @version v1.0.0
 * @since 2019/11/26 3:28 下午
 */
@Aspect
@Component
public class LogAopAspect {

    @Resource
    private LogService logService;

    /**
     * 这里我们使用注解的形式
     * 当然，我们也可以通过切点表达式直接指定需要拦截的package,需要拦截的class 以及 method
     * 切点表达式:   execution(...)
     */
    @Pointcut("@annotation(com.welike.shibo.aspect.annotation.AutoLog)")
    public void logPointCut() {}


    /**
     * 环绕通知 @Around，当然也可以使用@Before(当前通知)    @After(后置通知)
     * @param point
     * @return
     * @throws Throwable
     */
    @Around("logPointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = point.proceed();
        try {
            saveLog(point);
        } catch (Exception e){
            e.printStackTrace();
        }
        return result;
    }

    /**
     * 保存日志
     * @param joinPoint
     */
    private void saveLog(ProceedingJoinPoint joinPoint) {
        // 从切面织入点处通过反射机制获取织入点处的方法
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        // 获取切入点所在的方法
        Method method = signature.getMethod();
        Log log = new Log();
        log.setCreateTime(new Date());

        // 获取用户ip地址
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        HttpSession session  = request.getSession();
        AutoLog autoLog = method.getAnnotation(AutoLog.class);
        if(autoLog != null){
            try {
                if ("后台".equals(autoLog.operateType())){
                    SysUser user = (SysUser) session.getAttribute(Constants.SESSION_USER_INFO);
                    log.setOperationName(user.getUsername());
                } else if ("APP".equals(autoLog.operateType())){
                    User user = (User) session.getAttribute(Constants.ACCOUNT);
                    log.setOperationName(user.getPhone());
                } else {
                    log.setOperationName("游客");
                }
            } catch (Exception e){
                log.setOperationName("游客");
            }

            // 注解上的描述
            log.setOperationType(autoLog.operateType());
            log.setOperationState(autoLog.operateState());
        }
        // 获取请求的方法名
        String methodName = method.getName();
        log.setOperationAction(methodName);

        log.setIp(IpUtil.getIpAddr(request));
        try {
            log.setOperationResult("请求正常");
        } catch (Throwable e) {
            e.printStackTrace();
            log.setOperationResult(e.toString());
        }
        logService.save(log);
    }
}
